<!DOCTYPE html>
<html lang="zh-CN" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>什么是虚拟 dom | Roger</title>
    <meta name="description" content="A VitePress site">
    <link rel="preload stylesheet" href="/docs/assets/style.688cd82e.css" as="style">
    
    <script type="module" src="/docs/assets/app.73a16568.js"></script>
    <link rel="preload" href="/docs/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="/docs/assets/chunks/framework.906ebc88.js">
    <link rel="modulepreload" href="/docs/assets/chunks/theme.df409c6c.js">
    <link rel="modulepreload" href="/docs/assets/pages_interview_Vue_index.md.26456aa4.lean.js">
    <link rel="icon" href="favicon.ico">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-255ec12d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-ae3e3f51></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-ae3e3f51> Skip to content </a><!--]--><!----><header class="VPNav" data-v-255ec12d data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-0937f67c><div class="container" data-v-0937f67c><div class="title" data-v-0937f67c><div class="VPNavBarTitle has-sidebar" data-v-0937f67c data-v-86d1bed8><a class="title" href="/docs/" data-v-86d1bed8><!--[--><!--]--><!----><!--[-->Roger<!--]--><!--[--><!--[--><!--[--><!--[--><!--]--><!--]--><!--]--><!--]--></a></div></div><div class="content" data-v-0937f67c><div class="curtain" data-v-0937f67c></div><div class="content-body" data-v-0937f67c><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-0937f67c><!----></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-0937f67c data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/" tabindex="0" data-v-7f418b0f data-v-0b525393><!--[--><span data-v-0b525393>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/pages/frontend/" tabindex="0" data-v-7f418b0f data-v-0b525393><!--[--><span data-v-0b525393>前端</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/pages/browser/Chrome/eventLoop/" tabindex="0" data-v-7f418b0f data-v-0b525393><!--[--><span data-v-0b525393>浏览器</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink active" href="/docs/pages/interview/Vue/" tabindex="0" data-v-7f418b0f data-v-0b525393><!--[--><span data-v-0b525393>面试题</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/pages/source/Vue/render/" tabindex="0" data-v-7f418b0f data-v-0b525393><!--[--><span data-v-0b525393>框架源码</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-0937f67c data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-0937f67c data-v-40855f84 data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-a7b5672a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-a7b5672a><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-0937f67c data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-255ec12d data-v-5cfd5582><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-5cfd5582><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-5cfd5582><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-5cfd5582>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-5cfd5582 data-v-18201f51><button data-v-18201f51>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-255ec12d data-v-845b8fc6><div class="curtain" data-v-845b8fc6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-845b8fc6><span class="visually-hidden" id="sidebar-aria-label" data-v-845b8fc6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>前端</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/frontend/HTML/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/frontend/CSS/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>CSS</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>浏览器</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/browser/Chrome/eventLoop/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>事件循环</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/browser/Chrome/render/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>渲染原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>源码解析</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Vue</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/Vue/render/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>模版渲染</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/Vue/lifeCycle/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>生命周期</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/Vue/dataProxy/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>data数据代理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/Vue/nextTick/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>nextTick</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/Vue/watch/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>watch监听</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>React</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/React/PureComponent/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>PureComponent原理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/React/router/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>React路由配置</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/source/React/setState/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>setState使用及原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible has-active" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>面试题</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/interview/Vue/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/docs/pages/interview/HC/" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML&CSS</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-255ec12d data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-3f215769 data-v-ff0f39c8><div class="content" data-v-ff0f39c8><div class="outline-marker" data-v-ff0f39c8></div><div class="outline-title" data-v-ff0f39c8>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-ff0f39c8><span class="visually-hidden" id="doc-outline-aria-label" data-v-ff0f39c8> Table of Contents for current page </span><ul class="root" data-v-ff0f39c8 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _docs_pages_interview_Vue_index" data-v-6b87e69f><div><h2 id="vue-动态绑定样式" tabindex="-1">Vue 动态绑定样式 <a class="header-anchor" href="#vue-动态绑定样式" aria-label="Permalink to &quot;Vue 动态绑定样式&quot;">​</a></h2><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#6A737D;">&lt;!-- 第一种方式 --&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">:class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;[&#39;classA&#39;,&#39;classB&#39;]&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="color:#6A737D;">&lt;!-- 第二种方式 --&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">:class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;{classA:true,classB:false}&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="color:#6A737D;">&lt;!-- 第三种方式 --&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">:class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;{fontSize:&#39;16px&#39;,color: &#39;red&#39;}&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="color:#6A737D;">&lt;!-- 第四种方式 --&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">:class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;[{fontSize:&#39;16px&#39;,color: &#39;red&#39;}]&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h2 id="vue-router-的实现原理" tabindex="-1">vue-router 的实现原理 <a class="header-anchor" href="#vue-router-的实现原理" aria-label="Permalink to &quot;vue-router 的实现原理&quot;">​</a></h2><p><strong>hash 模式</strong></p><ol><li><p>localtion.hash 的值就是 url 地址 # 后的值，优点就是：在我们请求 HTTP 时，并不会把#后的值携带过去， 对后端没有影响，所以不会刷新页面</p></li><li><p>可以给 hash 的改变添加事件</p></li></ol><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">window.</span><span style="color:#B392F0;">addEventListener</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;hashchange&quot;</span><span style="color:#E1E4E8;">, func)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>每一次改变 hash（window.location.hash），都会在浏览器的访问历史中增加一个记录利用 hash 的以上特点，就可以来实现前端路由“更新视图但不重新请求页面”的功能了</p><blockquote><p>缺点： 路径中多了一个 # 号不美观</p></blockquote><p><strong>history 模式</strong></p><p>利用 H5 的新特性，pushState() 和 replaceState() 两个方法</p><p>这两个方法应用于浏览器的历史记录站，在当前已有的 back、forward、go 的基础之上，它们提供了对历史记录进行修改的功能。这两个方法有个共同的特点：当调用他们修改浏览器历史记录栈后，虽然当前 URL 改变了，但浏览器不会刷新页面，这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础</p><blockquote><p>但是页面可能会出现 404，需要后端配合</p></blockquote><h2 id="vue-router-有几种导航钩子" tabindex="-1">vue-router 有几种导航钩子？ <a class="header-anchor" href="#vue-router-有几种导航钩子" aria-label="Permalink to &quot;vue-router 有几种导航钩子？&quot;">​</a></h2><ol><li>全局守卫： <code>router.beforeEach</code></li><li>全局解析守卫： <code>router.beforeResolve</code></li><li>全局后置钩子： <code>router.afterEach</code></li><li>路由独享的守卫： <code>beforeEnter</code></li><li>组件内的守卫： <code>beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave</code></li></ol><h2 id="前端路由和后端路由的区别" tabindex="-1">前端路由和后端路由的区别 <a class="header-anchor" href="#前端路由和后端路由的区别" aria-label="Permalink to &quot;前端路由和后端路由的区别&quot;">​</a></h2><p><strong>前端路由</strong></p><ol><li>在页面不刷新的前提下，前端通过监听 url 地址的变化，展示不同的页面</li><li>实现前后端分离，SPA 单页面的发展，目前项目用的都是前端路由</li></ol><p>优点：</p><ol><li>用户体验良好，切换页面时不需要刷新页面，也不需要向后端发送请求，可以快速展示页面</li><li>可以通过手动修改 url 地址，访问指定路径</li><li>前后端分离，提高开发效率，现在很多框架都有路由模块</li></ol><p>缺点：</p><ol><li>使用浏览器的前进，后退键的时候会重新发送请求，没有合理地利用缓存</li><li>单页面无法记住之前滚动的位置，无法在前进，后退的时候记住滚动的位置</li></ol><p><strong>后端路由</strong></p><ol><li>浏览器在每次修改 url 地址时都会向后端发送请求，后端通过拼接 html 文件给前端渲染</li><li>如果用户网速较慢，可能会出现白屏的情况</li></ol><p>优点：</p><ol><li>分担了前端的压力，网页都是通过后端传过来的 html 渲染的</li></ol><p>缺点：</p><ol><li>当项目比较大时，后端的压力就比较大</li></ol><h2 id="refs-和-el-的用法" tabindex="-1">$refs 和 $el 的用法 <a class="header-anchor" href="#refs-和-el-的用法" aria-label="Permalink to &quot;\$refs 和 $el 的用法&quot;">​</a></h2><p><strong>$refs 有三种用法</strong></p><ol><li>ref 加在普通标签身上，通过 $refs.(ref 的值) 得到 dom 元素</li></ol><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">ref</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;div&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.$refs.div </span><span style="color:#6A737D;">// 这样就可以获取div的dom元素</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><ol start="2"><li>ref 加在子组件标签身上，通过 $refs.(ref 的值) 得到的是子组件的实例，可以使用组件的方法属性</li></ol><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#FDAEB7;font-style:italic;">child</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">ref</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;child&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#FDAEB7;font-style:italic;">child</span><span style="color:#E1E4E8;">&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.$refs.child </span><span style="color:#6A737D;">// 这样就可以获取子组件的实例</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><ol start="3"><li>获取自定义组件的 dom 元素的属性，比如获取 child 组件的 offsetTop 值, $el 获取的是真实的 dom</li></ol><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#FDAEB7;font-style:italic;">child</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">ref</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;child&quot;</span><span style="color:#E1E4E8;">&gt;&lt;/</span><span style="color:#FDAEB7;font-style:italic;">child</span><span style="color:#E1E4E8;">&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.$refs.child.$el.offsetTop </span><span style="color:#6A737D;">// 这样就可以获取子组件的offsetTop</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="vue-常用的修饰符" tabindex="-1">Vue 常用的修饰符 <a class="header-anchor" href="#vue-常用的修饰符" aria-label="Permalink to &quot;Vue 常用的修饰符&quot;">​</a></h2><ol><li>.prevent 阻止默认行为</li><li>.stop 阻止事件冒泡</li><li>.self 当 event.target 等于 被绑定的元素时触发，相当于事件发生在元素本身才会触发</li><li>.capture: 事件侦听，事件发生的时候会调用</li><li>.enter 点击了确认按钮</li><li>.lazy 懒更新</li><li>.trim 清空两侧空格</li><li>.number 只能输入数字 ......</li></ol><h2 id="v-if-和-v-show-的区别以及使用场景" tabindex="-1">v-if 和 v-show 的区别以及使用场景 <a class="header-anchor" href="#v-if-和-v-show-的区别以及使用场景" aria-label="Permalink to &quot;v-if 和 v-show 的区别以及使用场景&quot;">​</a></h2><p><strong>区别</strong></p><ol><li>隐藏原理： v-if 通过控制 dom 节点是否存在控制显示隐藏，v-show 通过切换 display 属性的 block 和 none 控制显示隐藏</li><li>编译过程： v-if 切换有一个局部编译/卸载的过程，切换过程中合适地销毁和重建内部的事件监听和子组件；v-show 只是简单的基于 css 切换</li><li>编译条件： v-if 只有当条件为 true 时才会编译，v-show 在任何条件下都会渲染，然后被缓存</li><li>性能消耗： v-if 在切换时消耗，v-show 在初次渲染时消耗</li></ol><p><strong>使用场景</strong></p><p>基于以上区别，因此，如果需要非常频繁地切换，则使用 v-show 较好；如果在运行时条件很少改变，则使用 v-if 较好。</p><h2 id="v-if-和-v-for-避免一起用" tabindex="-1">v-if 和 v-for 避免一起用 <a class="header-anchor" href="#v-if-和-v-for-避免一起用" aria-label="Permalink to &quot;v-if 和 v-for 避免一起用&quot;">​</a></h2><ol><li>v2 和 v3 v-if 和 v-for 的优先级是不一样的，在 v2 中，v-for 的优先级要高于 v-if，先循环再控制显示隐藏</li><li>v-for 的优先级更高，如果 v-if 的条件为 false，v-for 渲染完了，v-if 又把元素删除了，比较浪费性能</li></ol><h2 id="vuex-为什么要分模块并且加命名空间" tabindex="-1">Vuex 为什么要分模块并且加命名空间 <a class="header-anchor" href="#vuex-为什么要分模块并且加命名空间" aria-label="Permalink to &quot;Vuex 为什么要分模块并且加命名空间&quot;">​</a></h2><p>每一个模块都有一个独自的状态树，所有的状态最终会集中到一个比较大的对象中，当你的项目比较大时，state 文件的代码看起来就会非常的臃肿，不好维护，为了解决问题，vuex 允许我们通过 module 对象引入模块，每个模块都有独立的 state,getters,mutations,actions,甚至可以引入子模块</p><p>如果希望模块具有更高的<strong>封装度和复用性</strong>，你可以通过添加  <code>namespaced: true</code>  的方式使其成为带命名空间的模块。当模块被注册后，它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。</p><h2 id="vue-ssr" tabindex="-1">Vue SSR <a class="header-anchor" href="#vue-ssr" aria-label="Permalink to &quot;Vue SSR&quot;">​</a></h2><p>SSR 也就是服务端渲染，也就是 Vue 在客户端把标签渲染成 html 的工作放在服务器完成，然后发 html 传给客户端直接渲染</p><p><strong>优点：</strong></p><p>SSR 有更好的 SEO，并且首屏加载更快</p><p><strong>缺点：</strong></p><p>开发条件会受到限制，服务器端渲染只支持 beforeCreate 和 created 两个钩子，当我们需要一些外部扩展库时需要特殊处理，服务端渲染应用程序也需要处于 Node.js 的运行环境。</p><p>服务器会有更大的负载需求</p><h2 id="函数式组件和普通组件有啥区别" tabindex="-1">函数式组件和普通组件有啥区别？ <a class="header-anchor" href="#函数式组件和普通组件有啥区别" aria-label="Permalink to &quot;函数式组件和普通组件有啥区别？&quot;">​</a></h2><ol><li>不维护响应数据</li><li>没有 instance 实例<br> 所以在组件内部没有办法像传统组件一样通过 this 来访问组件属性<br> 实现原理见下面代码中的中文注释</li><li>渲染快</li><li>没有实例，意味着没有（this）</li><li>有生命周期（没有钩子函数，没有响应式数据）</li></ol><h2 id="vue-的性能优化" tabindex="-1">Vue 的性能优化 <a class="header-anchor" href="#vue-的性能优化" aria-label="Permalink to &quot;Vue 的性能优化&quot;">​</a></h2><ul><li>使用函数式组件</li><li>data 中的数据嵌套层级不要太深</li><li>在不同的场景合理运用 <code>v-if</code> <code>v-show</code></li><li>图片懒加载</li><li>路由懒加载</li><li>预渲染 添加 loading 或者 骨架屏</li><li>SSR 服务端渲染</li><li>第三方的插件按需引入</li><li>提高代码复用率 组件化 模块化</li><li>使用 CDN 加速</li><li><code>keep-alive</code>缓存组件</li><li>合理运用 <code>computed</code></li><li>表格或者列表数据较多时，使用虚拟表格或者虚拟列表</li><li>v-for 必须添加 key 值，key 值最好是唯一的</li></ul><h2 id="mixin-混入运用场景" tabindex="-1">mixin 混入运用场景 <a class="header-anchor" href="#mixin-混入运用场景" aria-label="Permalink to &quot;mixin 混入运用场景&quot;">​</a></h2><p>在日常的开发中，我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码，这些代码的功能相对独立，可以通过 Vue 的 mixin 功能抽离公共的业务逻辑，原理类似“对象的继承”，当组件初始化时会调用 mergeOptions 方法进行合并，采用策略模式针对不同的属性进行合并。当组件和混入对象含有同名选项时，这些选项将以恰当的方式进行“合并”。</p><h2 id="keep-alive-使用场景原理" tabindex="-1">keep-alive 使用场景原理 <a class="header-anchor" href="#keep-alive-使用场景原理" aria-label="Permalink to &quot;keep-alive 使用场景原理&quot;">​</a></h2><p>keep-alive 是 vue 内置的组件，可以实现对组件的缓存，切换组件时不会对组件进行销毁</p><ul><li>常用的两个属性 <code>include</code> 包含的组件被缓存 <code>exclude</code> 包含的组件不被缓存</li><li>被缓存的组件会多两个生命周期 actived/deactived 用来得知当前组件激活状态</li><li>keep-alive 的中还运用了 LRU(最近最少使用) 算法，选择最近最久未使用的组件予以淘汰</li></ul><h2 id="vue-set-方法原理" tabindex="-1">Vue.set 方法原理 <a class="header-anchor" href="#vue-set-方法原理" aria-label="Permalink to &quot;Vue.set 方法原理&quot;">​</a></h2><p>有两种修改数据的方式是不会触发视图更新的</p><ol><li>初始化完成，data 中的数据已经劫持完了，给响应式的对象新增属性</li><li>通过数组索引修改值</li></ol><p><strong>Vue.set 的原理</strong></p><p>因为响应式数据 我们给对象和数组本身都增加了<strong>ob</strong>属性，代表的是 Observer 实例。当给对象新增不存在的属性 首先会把新的属性进行响应式跟踪 然后会触发对象<strong>ob</strong>的 dep 收集到的 watcher 去更新，当修改数组索引时我们调用数组本身的 splice 方法去更新数组</p><h2 id="vue-extend-作用和原理" tabindex="-1">Vue.extend 作用和原理 <a class="header-anchor" href="#vue-extend-作用和原理" aria-label="Permalink to &quot;Vue.extend 作用和原理&quot;">​</a></h2><p>官方解释：Vue.extend 使用基础 Vue 构造器，创建一个“子类”。参数是一个包含组件选项的对象。</p><p>其实就是一个子类构造器 是 Vue 组件的核心 api 实现思路就是使用原型继承的方法返回了 Vue 的子类 并且利用 mergeOptions 把传入组件的 options 和父类的 options 进行了合并</p><h2 id="自定义指令" tabindex="-1">自定义指令 <a class="header-anchor" href="#自定义指令" aria-label="Permalink to &quot;自定义指令&quot;">​</a></h2><p>指令本质上是装饰器，是 vue 对 HTML 元素的扩展，给 HTML 元素增加自定义功能。vue 编译 DOM 时，会找到指令对象，执行指令的相关方法。</p><p>自定义指令有五个生命周期（也叫钩子函数），分别是 bind、inserted、update、componentUpdated、unbind</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#79B8FF;">1.</span><span style="color:#E1E4E8;"> bind：只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;">2.</span><span style="color:#E1E4E8;"> inserted：</span><span style="color:#B392F0;">被绑定元素插入父节点时调用</span><span style="color:#E1E4E8;"> (仅保证父节点存在，但不一定已被插入文档中)。</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;">3.</span><span style="color:#E1E4E8;"> update：被绑定于元素所在的模板更新时调用，而无论绑定值是否变化。通过比较更新前后的绑定值，可以忽略不必要的模板更新。</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;">4.</span><span style="color:#E1E4E8;"> componentUpdated：被绑定元素所在模板完成一次更新周期时调用。</span></span>
<span class="line"></span>
<span class="line"><span style="color:#79B8FF;">5.</span><span style="color:#E1E4E8;"> unbind：只调用一次，指令与元素解绑时调用。</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p><strong>原理</strong></p><p>1.在生成 ast 语法树时，遇到指令会给当前元素添加 directives 属性</p><p>2.通过 genDirectives 生成指令代码</p><p>3.在 patch 前将指令的钩子提取到 cbs 中,在 patch 过程中调用对应的钩子</p><p>4.当执行指令对应钩子函数时，调用对应指令定义的方法</p><h2 id="vue-模板编译" tabindex="-1">Vue 模板编译 <a class="header-anchor" href="#vue-模板编译" aria-label="Permalink to &quot;Vue 模板编译&quot;">​</a></h2><p>在我之前的文章里有详细说明 <a href="https://juejin.cn/post/7225891176532721725#heading-1" target="_blank" rel="noreferrer">Vue 渲染流程</a></p><h2 id="监听路由参数发生变化" tabindex="-1">监听路由参数发生变化 <a class="header-anchor" href="#监听路由参数发生变化" aria-label="Permalink to &quot;监听路由参数发生变化&quot;">​</a></h2><ol><li>Vue-router 在地址上的 params 发生变化时是做了优化的，比如商品详情页需要更新不同的商品，其实只需要更新数据即可，如果路由重新跳转本页面，则要经过组件初始化，生成 dom 等操作，是非常消耗性能的，所以 Vue-router 在地址相同参数不同时，选择复用组件，如果想监听路由参数发生变化也是有办法的</li></ol><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#6A737D;">// 第一种写法</span></span>
<span class="line"><span style="color:#B392F0;">watch</span><span style="color:#E1E4E8;">: {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">$route</span><span style="color:#E1E4E8;">(to,from){</span></span>
<span class="line"><span style="color:#E1E4E8;">    console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(to) </span><span style="color:#6A737D;">// to 表示 去</span></span>
<span class="line"><span style="color:#E1E4E8;">    console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(from) </span><span style="color:#6A737D;">// from 表示 来自</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 路由变化后的操作</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;">..</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">// 第二种写法</span></span>
<span class="line"><span style="color:#B392F0;">watch</span><span style="color:#E1E4E8;">: {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">$route</span><span style="color:#E1E4E8;">: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">handler</span><span style="color:#E1E4E8;">(to,from){</span></span>
<span class="line"><span style="color:#E1E4E8;">        console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(to)</span></span>
<span class="line"><span style="color:#E1E4E8;">        console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(from)</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#6A737D;">// 路由变化后的操作</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;">..</span></span>
<span class="line"><span style="color:#E1E4E8;">    },</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">deep</span><span style="color:#E1E4E8;">: </span><span style="color:#79B8FF;">true</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;">// 深度监听</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">// 第三种写法</span></span>
<span class="line"><span style="color:#B392F0;">watch</span><span style="color:#E1E4E8;">: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#9ECBFF;">&#39;$route&#39;</span><span style="color:#E1E4E8;">:</span><span style="color:#9ECBFF;">&#39;getPath&#39;</span></span>
<span class="line"><span style="color:#E1E4E8;">},</span></span>
<span class="line"><span style="color:#B392F0;">methods</span><span style="color:#E1E4E8;">: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">getPath</span><span style="color:#E1E4E8;">(to, from){</span></span>
<span class="line"><span style="color:#E1E4E8;">	    console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.$route.path);</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br></div></div><h2 id="vue-中-data-的数据失去响应式的原因" tabindex="-1">Vue 中 data 的数据失去响应式的原因 <a class="header-anchor" href="#vue-中-data-的数据失去响应式的原因" aria-label="Permalink to &quot;Vue 中 data 的数据失去响应式的原因&quot;">​</a></h2><ol><li>在数据初始化后给 data 中的对象添加属性，添加的属性是没有 getter 和 setter 的，可以使用 Vue 提供的$set 方法</li></ol><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">obj</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {}</span></span>
<span class="line"><span style="color:#E1E4E8;">Vue.</span><span style="color:#B392F0;">set</span><span style="color:#E1E4E8;">(obj, key, value)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h2 id="多层父子组件通讯" tabindex="-1">多层父子组件通讯 <a class="header-anchor" href="#多层父子组件通讯" aria-label="Permalink to &quot;多层父子组件通讯&quot;">​</a></h2><p>有时候需要通讯的组件不是直接的父子组件，而是祖父和孙子，嵌套的层级比较多的情况下，需要传递的事件和属性比较多，会导致代码混乱，这个时候就需要用到 Vue 提供的更高阶方法：provide/inject</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#6A737D;">// 父级组件提供 &#39;foo&#39;</span></span>
<span class="line"><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> Provider </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">data</span><span style="color:#E1E4E8;">(){</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">            foo: </span><span style="color:#9ECBFF;">&#39;bar&#39;</span></span>
<span class="line"><span style="color:#E1E4E8;">        }</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">    provide: {</span></span>
<span class="line"><span style="color:#E1E4E8;">        fooProvide: </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.fooFn </span><span style="color:#6A737D;">// 传递一个引用类型函数过去</span></span>
<span class="line"><span style="color:#E1E4E8;">    },</span></span>
<span class="line"><span style="color:#E1E4E8;">    methods:{</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#B392F0;">fooFn</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">            </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.foo</span></span>
<span class="line"><span style="color:#E1E4E8;">        }</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> Child </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">    inject: [</span><span style="color:#9ECBFF;">&#39;fooProvide&#39;</span><span style="color:#E1E4E8;">],</span></span>
<span class="line"><span style="color:#E1E4E8;">    computed:{</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#B392F0;">fooComputed</span><span style="color:#E1E4E8;">(){</span></span>
<span class="line"><span style="color:#E1E4E8;">            </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">fooProvide</span><span style="color:#E1E4E8;">() </span><span style="color:#6A737D;">// 因为传递过来是个引用类型的函数</span></span>
<span class="line"><span style="color:#E1E4E8;">        }</span></span>
<span class="line"><span style="color:#E1E4E8;">    },</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">created</span><span style="color:#E1E4E8;"> () {</span></span>
<span class="line"><span style="color:#E1E4E8;">        console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.fooComputed)</span></span>
<span class="line"><span style="color:#E1E4E8;">    } </span><span style="color:#6A737D;">// ...</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><h2 id="vuex-刷新页面数据丢失怎么解决" tabindex="-1">Vuex 刷新页面数据丢失怎么解决？ <a class="header-anchor" href="#vuex-刷新页面数据丢失怎么解决" aria-label="Permalink to &quot;Vuex 刷新页面数据丢失怎么解决？&quot;">​</a></h2><ol><li>把 vuex 的数据存储到 localStorage 中,每次页面刷新在 localStorage 中取</li><li>在页面刷新的时候向后端获取数据，动态更新数据</li><li>在父页面向后台请求远程数据，并且在页面刷新前将 vuex 的数据先保存至 sessionStorage（以防请求数据量过大页面加载时拿不到返回的数据</li></ol><h2 id="简述-vuex" tabindex="-1">简述 Vuex <a class="header-anchor" href="#简述-vuex" aria-label="Permalink to &quot;简述 Vuex&quot;">​</a></h2><p>Vex 有 5 种属性，分别是 state、getter、mutation、action、module：</p><p><strong>1、state</strong></p><p>Vuex 使用单一状态树,即每个应用将仅仅包含一个 store 实例，但单一状态树和模块化并不冲突。存放的数据状态，不可以直接修改里面的数据。</p><p><strong>2、getters</strong></p><p>类似 vue 的计算属性，主要用来过滤一些数据。</p><p><strong>3、mutations</strong></p><p>mutations 定义的方法动态修改 Vuex 的 store 中的状态或数据。</p><p><strong>4、actions</strong></p><p>actions 可以理解为通过将 mutations 里面处里数据的方法变成可异步的处理数据的方法，简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">store</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">new</span><span style="color:#E1E4E8;"> Vuex.</span><span style="color:#B392F0;">Store</span><span style="color:#E1E4E8;">({</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//store实例</span></span>
<span class="line"><span style="color:#E1E4E8;">  state: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    count: </span><span style="color:#79B8FF;">0</span><span style="color:#E1E4E8;">,</span></span>
<span class="line"><span style="color:#E1E4E8;">  },</span></span>
<span class="line"><span style="color:#E1E4E8;">  mutations: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">increment</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">state</span><span style="color:#E1E4E8;">) {</span></span>
<span class="line"><span style="color:#E1E4E8;">      state.count</span><span style="color:#F97583;">++</span></span>
<span class="line"><span style="color:#E1E4E8;">    },</span></span>
<span class="line"><span style="color:#E1E4E8;">  },</span></span>
<span class="line"><span style="color:#E1E4E8;">  actions: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">increment</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">context</span><span style="color:#E1E4E8;">) {</span></span>
<span class="line"><span style="color:#E1E4E8;">      context.</span><span style="color:#B392F0;">commit</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;increment&quot;</span><span style="color:#E1E4E8;">)</span></span>
<span class="line"><span style="color:#E1E4E8;">    },</span></span>
<span class="line"><span style="color:#E1E4E8;">  },</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><p><strong>5、modules</strong></p><p>项目特别复杂的时候，可以让每一个模块拥有自己的 state、mutation、action、getters,使得结构非常清晰，方便管理。</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">moduleA</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  state: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> },</span></span>
<span class="line"><span style="color:#E1E4E8;">  mutations: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> },</span></span>
<span class="line"><span style="color:#E1E4E8;">  actions: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> },</span></span>
<span class="line"><span style="color:#E1E4E8;">  getters: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">moduleB</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  state: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> },</span></span>
<span class="line"><span style="color:#E1E4E8;">  mutations: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> },</span></span>
<span class="line"><span style="color:#E1E4E8;">  actions: { </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;"> }</span></span>
<span class="line"><span style="color:#E1E4E8;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">store</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">new</span><span style="color:#E1E4E8;"> Vuex.</span><span style="color:#B392F0;">Store</span><span style="color:#E1E4E8;">({</span></span>
<span class="line"><span style="color:#E1E4E8;">  modules: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    a: moduleA,</span></span>
<span class="line"><span style="color:#E1E4E8;">    b: moduleB</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><h2 id="强制刷新视图更新" tabindex="-1">强制刷新视图更新 <a class="header-anchor" href="#强制刷新视图更新" aria-label="Permalink to &quot;强制刷新视图更新&quot;">​</a></h2><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">forceUpdate</span><span style="color:#E1E4E8;">() </span><span style="color:#6A737D;">// 调用后页面视图就达到最新了</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="过滤器" tabindex="-1">过滤器 <a class="header-anchor" href="#过滤器" aria-label="Permalink to &quot;过滤器&quot;">​</a></h2><ol><li>局部过滤器</li></ol><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;{{ num | filter }}&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">```s ```js filters: { filter(val){ return val +1 } }</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><ol start="2"><li>全局过滤器</li></ol><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;{{ num | filter }}&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">Vue.</span><span style="color:#B392F0;">filter</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;filter&quot;</span><span style="color:#E1E4E8;">, (</span><span style="color:#FFAB70;">val</span><span style="color:#E1E4E8;">) </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> val </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h2 id="vue-组件-data-为什么必须是函数" tabindex="-1">Vue 组件 data 为什么必须是函数 <a class="header-anchor" href="#vue-组件-data-为什么必须是函数" aria-label="Permalink to &quot;Vue 组件 data 为什么必须是函数&quot;">​</a></h2><p>data 是一个函数的话，这样每复用一次组件，就会返回一份新的<code>data</code>，类似于给每个组件实例创建一个私有的数据空间，让各个组件实例维护各自的数据。而单纯的写成对象形式，就使得所有组件实例共用了一份<code>data</code>，就会造成一个变了全都会变的结果。</p><h2 id="自定义指令-1" tabindex="-1">自定义指令 <a class="header-anchor" href="#自定义指令-1" aria-label="Permalink to &quot;自定义指令&quot;">​</a></h2><ol><li>全局注册</li></ol><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">Vue.</span><span style="color:#B392F0;">directive</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;focus&quot;</span><span style="color:#E1E4E8;">, {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">inseted</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">el</span><span style="color:#E1E4E8;">) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    el.</span><span style="color:#B392F0;">focus</span><span style="color:#E1E4E8;">()</span></span>
<span class="line"><span style="color:#E1E4E8;">  },</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><ol start="2"><li>局部注册</li></ol><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#B392F0;">directives</span><span style="color:#E1E4E8;">:{</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">focus</span><span style="color:#E1E4E8;">: {</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#B392F0;">inserted</span><span style="color:#E1E4E8;">(el){</span></span>
<span class="line"><span style="color:#E1E4E8;">            el.</span><span style="color:#B392F0;">focus</span><span style="color:#E1E4E8;">()</span></span>
<span class="line"><span style="color:#E1E4E8;">        }</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h2 id="nexttick-用法及原理" tabindex="-1">nextTick 用法及原理 <a class="header-anchor" href="#nexttick-用法及原理" aria-label="Permalink to &quot;nextTick 用法及原理&quot;">​</a></h2><ol><li>nextTick 存在的意义</li></ol><p>因为 vue 采用的<strong>异步更新策略</strong>，当监听到数据发生变化的时候不会立即去更新 DOM，<br> 而是开启一个任务队列，并缓存在同一事件循环中发生的所有数据变更;<br> 这种做法带来的好处就是可以将多次数据更新合并成一次，减少操作 DOM 的次数，<br> 如果不采用这种方法，假设数据改变 100 次就要去更新 100 次 DOM，而频繁的 DOM 更新是很耗性能的；</p><ol start="2"><li>nextTick 的作用</li></ol><p>nextTick 接收一个回调函数作为参数，并将这个回调函数延迟到 DOM 更新后才执行；<br><strong>使用场景</strong>：想要操作  <em>基于最新数据生成的 DOM</em>  时，就将这个操作放在 nextTick 的回调中</p><ol start="3"><li>nextTick 实现原理</li></ol><p>将传入的回调函数包装成异步任务，异步任务又分微任务和宏任务，为了尽快执行所以优先选择微任务； nextTick 提供了四种异步方法 Promise.then、MutationObserver、setImmediate、setTimeout(fn,0)</p><h2 id="router-和-route-的区别" tabindex="-1">$router 和$route 的区别 <a class="header-anchor" href="#router-和-route-的区别" aria-label="Permalink to &quot;\$router 和$route 的区别&quot;">​</a></h2><ol><li><code>$router</code>是<code>VueRouter</code>的实例对象，想跳转页面，可以使用<code>this.$router.push</code>或者<code>go</code>,<code>back</code></li><li><code>$route</code>指的是当前路由地址信息，有<code>path</code>,<code>params</code>,<code>query</code>....</li></ol><h2 id="vue-cli-生成的项目文件夹-assets-和-public-static-的区别" tabindex="-1">vue-cli 生成的项目文件夹 assets 和 public(static) 的区别 <a class="header-anchor" href="#vue-cli-生成的项目文件夹-assets-和-public-static-的区别" aria-label="Permalink to &quot;vue-cli 生成的项目文件夹 assets 和 public(static) 的区别&quot;">​</a></h2><p>vue-cli2 生成的项目目录是 static</p><p>vue-cli3 以上生成的项目目录是 public</p><ul><li>相同点：</li></ul><p>assets 和 public(static) 都是存放静态资源的文件。项目所需要的静态文件、图片、样式文件都可以放在这两个文件夹下</p><ul><li>不同点：</li></ul><p>在 assets 中存放的静态资源，在项目打包时会将这些静态资源与代码、index.html 文件一起一同进行打包压缩，上传到服务器</p><p>在 public(static)中存放的静态资源，不会被打包压缩格式化等流程，而是直接进入打包好的目录，直接上传到服务器</p><h2 id="sync-修饰符" tabindex="-1">.sync 修饰符 <a class="header-anchor" href="#sync-修饰符" aria-label="Permalink to &quot;.sync 修饰符&quot;">​</a></h2><ol><li><code>.sync</code>用于父传子时使用,类似于<code>v-model</code>，<code>.sync</code>也是语法糖，v-model 针对的是表单元素，sync 是在父子传值时使用</li><li>平时我们父子传值使用的是自定义属性，和自定义事件</li></ol><p><em>用简单的代码来描述</em></p><p><strong>父组件</strong></p><div class="language- line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark"><code><span class="line"><span style="color:#e1e4e8;">&lt;template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">    &lt;Child :num=&quot;num&quot; @add=&quot;add&quot;/&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;/div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;script&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">import child from &#39;@/views/child.vue&#39;</span></span>
<span class="line"><span style="color:#e1e4e8;">export default {</span></span>
<span class="line"><span style="color:#e1e4e8;">  data() {</span></span>
<span class="line"><span style="color:#e1e4e8;">    return {</span></span>
<span class="line"><span style="color:#e1e4e8;">      num: 1</span></span>
<span class="line"><span style="color:#e1e4e8;">    }</span></span>
<span class="line"><span style="color:#e1e4e8;">  },</span></span>
<span class="line"><span style="color:#e1e4e8;">  methods: {</span></span>
<span class="line"><span style="color:#e1e4e8;">    add(val){</span></span>
<span class="line"><span style="color:#e1e4e8;">      this.num += val</span></span>
<span class="line"><span style="color:#e1e4e8;">    }</span></span>
<span class="line"><span style="color:#e1e4e8;">  },</span></span>
<span class="line"><span style="color:#e1e4e8;">  components: {</span></span>
<span class="line"><span style="color:#e1e4e8;">    Child: child</span></span>
<span class="line"><span style="color:#e1e4e8;">  }</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/script&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><p><strong>子组件</strong></p><div class="language- line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark"><code><span class="line"><span style="color:#e1e4e8;">&lt;template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">    &lt;div&gt;{{ num }}&lt;/div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">    &lt;button @click=&quot;add&quot;&gt;按钮&lt;/button&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;/div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;script&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">export default {</span></span>
<span class="line"><span style="color:#e1e4e8;">  data() {</span></span>
<span class="line"><span style="color:#e1e4e8;">    return {}</span></span>
<span class="line"><span style="color:#e1e4e8;">  },</span></span>
<span class="line"><span style="color:#e1e4e8;">  props: [&#39;num&#39;],</span></span>
<span class="line"><span style="color:#e1e4e8;">  methods: {</span></span>
<span class="line"><span style="color:#e1e4e8;">    add() {</span></span>
<span class="line"><span style="color:#e1e4e8;">      this.$emit(&#39;add&#39;, this.num + 1)</span></span>
<span class="line"><span style="color:#e1e4e8;">    }</span></span>
<span class="line"><span style="color:#e1e4e8;">  }</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/script&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p><code>.sync</code>修饰符就是我们上述操作的语法糖，内部帮我们修改了数据，简单看一下如何使用</p><p><strong>父组件</strong></p><div class="language- line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark"><code><span class="line"><span style="color:#e1e4e8;">&lt;template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">    &lt;Child :num.sync=&quot;num&quot; /&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;/div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;script&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">import child from &#39;@/views/child.vue&#39;</span></span>
<span class="line"><span style="color:#e1e4e8;">export default {</span></span>
<span class="line"><span style="color:#e1e4e8;">  data() {</span></span>
<span class="line"><span style="color:#e1e4e8;">    return {</span></span>
<span class="line"><span style="color:#e1e4e8;">      num: 1</span></span>
<span class="line"><span style="color:#e1e4e8;">    }</span></span>
<span class="line"><span style="color:#e1e4e8;">  },</span></span>
<span class="line"><span style="color:#e1e4e8;">  components: {</span></span>
<span class="line"><span style="color:#e1e4e8;">    Child: child</span></span>
<span class="line"><span style="color:#e1e4e8;">  }</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/script&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p>父组件在传值的时候加上<code>.sync</code>修饰符等于 <code>&lt;Child :num=&quot;num&quot; @update:num=&quot;val =&gt; num = val&quot;/&gt;</code>,我们可以节省了监听自定义事件触发的代码</p><p><strong>子组件</strong></p><div class="language- line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark"><code><span class="line"><span style="color:#e1e4e8;">&lt;template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">    &lt;div&gt;{{ num }}&lt;/div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">    &lt;button @click=&quot;add&quot;&gt;按钮&lt;/button&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">  &lt;/div&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/template&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;script&gt;</span></span>
<span class="line"><span style="color:#e1e4e8;">export default {</span></span>
<span class="line"><span style="color:#e1e4e8;">  data() {</span></span>
<span class="line"><span style="color:#e1e4e8;">    return {}</span></span>
<span class="line"><span style="color:#e1e4e8;">  },</span></span>
<span class="line"><span style="color:#e1e4e8;">  props: [&#39;num&#39;],</span></span>
<span class="line"><span style="color:#e1e4e8;">  methods: {</span></span>
<span class="line"><span style="color:#e1e4e8;">    add() {</span></span>
<span class="line"><span style="color:#e1e4e8;">      this.$emit(&#39;update:num&#39;, this.num + 1)</span></span>
<span class="line"><span style="color:#e1e4e8;">    }</span></span>
<span class="line"><span style="color:#e1e4e8;">  }</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span>
<span class="line"><span style="color:#e1e4e8;">&lt;/script&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p>使用<code>this.$emit(&#39;update:属性名&#39;,要修改的值)</code>触发自定义事件 Vue 内部监听到就会修改父组件的数据</p><h1 id="什么是虚拟-dom" tabindex="-1">什么是虚拟 dom <a class="header-anchor" href="#什么是虚拟-dom" aria-label="Permalink to &quot;什么是虚拟 dom&quot;">​</a></h1><p>虚拟 dom 就是把页面上的标签转换成 js 对象，用对象属性来描述节点，最后通过虚拟 dom 生成真实 dom</p><p>通过真实 dom 映射虚拟 dom</p><div class="language-html line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#E1E4E8;">&lt;</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;box&quot;</span><span style="color:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">  &lt;</span><span style="color:#85E89D;">h1</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">&quot;title&quot;</span><span style="color:#E1E4E8;">&gt;标题&lt;/</span><span style="color:#85E89D;">h1</span><span style="color:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">&lt;/</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">&gt;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>虚拟 dom</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> element </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  tagName: </span><span style="color:#9ECBFF;">&quot;div&quot;</span><span style="color:#E1E4E8;">, </span><span style="color:#6A737D;">// 节点标签名</span></span>
<span class="line"><span style="color:#E1E4E8;">  props: {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// DOM的属性，用一个对象存储键值对</span></span>
<span class="line"><span style="color:#E1E4E8;">    class: </span><span style="color:#9ECBFF;">&quot;box&quot;</span><span style="color:#E1E4E8;">,</span></span>
<span class="line"><span style="color:#E1E4E8;">  },</span></span>
<span class="line"><span style="color:#E1E4E8;">  children: [</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 该节点的子节点</span></span>
<span class="line"><span style="color:#E1E4E8;">    { tagName: </span><span style="color:#9ECBFF;">&quot;h1&quot;</span><span style="color:#E1E4E8;">, props: { class: </span><span style="color:#9ECBFF;">&quot;title&quot;</span><span style="color:#E1E4E8;"> }, children: [] }, </span><span style="color:#6A737D;">// 以此类推</span></span>
<span class="line"><span style="color:#E1E4E8;">  ],</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><h2 id="为什么需要虚拟-dom" tabindex="-1">为什么需要虚拟 dom <a class="header-anchor" href="#为什么需要虚拟-dom" aria-label="Permalink to &quot;为什么需要虚拟 dom&quot;">​</a></h2><ol><li><strong>操作原生 DOM 慢，js 运行效率高</strong>，我们可以将 DOM 对比操作放在 JS 层，提高效率。 因为 DOM 操作的执行速度远不如 Javascript 的运算速度快，因此，把大量的 DOM 操作搬运到 Javascript 中，运用 patching 算法来计算出真正需要更新的节点，最大限度地减少 DOM 操作，从而显著提高性能</li><li>操作真实 DOM 会触发浏览器渲染，又需要走一次渲染流程，引发重排等等，效率非常低</li><li>vnode 的关键在于，大量的数据操作，vnode 可以避免很多 dom 不必要的修改，提升渲染性能</li></ol><h2 id="vue2-如何监听数组变化" tabindex="-1">Vue2 如何监听数组变化 <a class="header-anchor" href="#vue2-如何监听数组变化" aria-label="Permalink to &quot;Vue2 如何监听数组变化&quot;">​</a></h2><p>因为 Object.defineProperty()只能监听对象，所以 Vue 对数组劫持，使用的是重写数组方法，当数组中嵌套了对象，还是使用 Object.defineProperty()，我们在项目通常都是使用数组方法更改数组，splice,pop,push......</p><p>直接上代码</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark"><code><span class="line"><span style="color:#6A737D;">// 1. 获取原来的数组方法</span></span>
<span class="line"><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> oldArrayProtoMethods </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Array</span><span style="color:#E1E4E8;">.</span><span style="color:#79B8FF;">prototype</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">// 2. 继承</span></span>
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> ArrayMethods </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> Object.</span><span style="color:#B392F0;">create</span><span style="color:#E1E4E8;">(oldArrayProtoMethods)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">// 3. 劫持数组里面的所有方法</span></span>
<span class="line"><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> methods </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> [</span><span style="color:#9ECBFF;">&quot;push&quot;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&quot;pop&quot;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&quot;shift&quot;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&quot;unshift&quot;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&quot;splice&quot;</span><span style="color:#E1E4E8;">] </span><span style="color:#6A737D;">// 常用改变数组的方法</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">methods.</span><span style="color:#B392F0;">forEach</span><span style="color:#E1E4E8;">((</span><span style="color:#FFAB70;">item</span><span style="color:#E1E4E8;">) </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  ArrayMethods[item] </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;"> (</span><span style="color:#F97583;">...</span><span style="color:#FFAB70;">args</span><span style="color:#E1E4E8;">) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 调用原来的方法</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> result </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> oldArrayProtoMethods[item].</span><span style="color:#B392F0;">apply</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">, args)</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 这里做了不同方法的一些操作</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> result</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>后面把 data 中的数组原型指向我们重写的原型对象，每次调用方法就可以监听到了，这也是为什么 vue2 无法监听通过索引值修改数组的值</p><h2 id="computed-和-watch" tabindex="-1">computed 和 watch <a class="header-anchor" href="#computed-和-watch" aria-label="Permalink to &quot;computed 和 watch&quot;">​</a></h2><p><code>Computed</code>本质是一个具备缓存的 watcher，依赖的属性发生变化就会更新视图。 适用于计算比较消耗性能的计算场景。当表达式过于复杂时，在模板中放入过多逻辑会让模板难以维护，可以将复杂的逻辑放入计算属性中处理。</p><p><code>Watch</code>没有缓存性，更多的是观察的作用，可以监听某些数据执行回调。当我们需要深度监听对象中的属性时，可以打开<code>deep：true</code>选项，这样便会对对象中的每一项进行监听。这样会带来性能问题，优化的话可以使用<code>字符串形式</code>监听</p></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-37656e44><!--[--><!--]--><!----><nav class="prev-next" data-v-37656e44><div class="pager" data-v-37656e44><a class="pager-link prev" href="/docs/pages/source/React/setState/" data-v-37656e44><span class="desc" data-v-37656e44>Previous page</span><span class="title" data-v-37656e44>setState使用及原理</span></a></div><div class="pager" data-v-37656e44><a class="pager-link next" href="/docs/pages/interview/HC/" data-v-37656e44><span class="desc" data-v-37656e44>Next page</span><span class="title" data-v-37656e44>HTML&CSS</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"pages_browser_chrome_eventloop_index.md\":\"5289ad5f\",\"pages_frontend_css_index.md\":\"33d7f8f0\",\"pages_frontend_js_index.md\":\"071be8ee\",\"pages_source_vue_dataproxy_index.md\":\"2190e5bb\",\"pages_source_react_router_index.md\":\"aee956e0\",\"pages_frontend_html_index.md\":\"d07d2697\",\"pages_frontend_index.md\":\"9602a34e\",\"pages_source_vue_render_index.md\":\"82ef8cd2\",\"index.md\":\"f1fd9f38\",\"pages_source_vue_lifecycle_index.md\":\"e821fde5\",\"pages_source_vue_nexttick_index.md\":\"77c4fcb8\",\"pages_source_react_setstate_index.md\":\"79ab1da8\",\"pages_browser_chrome_render_index.md\":\"ef66fcb1\",\"pages_source_vue_watch_index.md\":\"07309914\",\"pages_source_react_purecomponent_index.md\":\"1489604b\",\"pages_interview_hc_index.md\":\"50eee13c\",\"pages_interview_vue_index.md\":\"26456aa4\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"Roger\",\"description\":\"A VitePress site\",\"base\":\"/docs/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"前端\",\"link\":\"/pages/frontend/\"},{\"text\":\"浏览器\",\"link\":\"/pages/browser/Chrome/eventLoop/\"},{\"text\":\"面试题\",\"link\":\"/pages/interview/Vue/\"},{\"text\":\"框架源码\",\"link\":\"/pages/source/Vue/render/\"}],\"sidebar\":[{\"text\":\"前端\",\"collapsed\":true,\"items\":[{\"text\":\"HTML\",\"link\":\"/pages/frontend/HTML/\"},{\"text\":\"CSS\",\"link\":\"/pages/frontend/CSS/\"}]},{\"text\":\"浏览器\",\"collapsed\":true,\"items\":[{\"text\":\"事件循环\",\"link\":\"/pages/browser/Chrome/eventLoop/\"},{\"text\":\"渲染原理\",\"link\":\"/pages/browser/Chrome/render/\"}]},{\"text\":\"源码解析\",\"collapsed\":true,\"items\":[{\"text\":\"Vue\",\"collapsed\":true,\"items\":[{\"text\":\"模版渲染\",\"link\":\"/pages/source/Vue/render/\"},{\"text\":\"生命周期\",\"link\":\"/pages/source/Vue/lifeCycle/\"},{\"text\":\"data数据代理\",\"link\":\"/pages/source/Vue/dataProxy/\"},{\"text\":\"nextTick\",\"link\":\"/pages/source/Vue/nextTick/\"},{\"text\":\"watch监听\",\"link\":\"/pages/source/Vue/watch/\"}]},{\"text\":\"React\",\"collapsed\":true,\"items\":[{\"text\":\"PureComponent原理\",\"link\":\"/pages/source/React/PureComponent/\"},{\"text\":\"React路由配置\",\"link\":\"/pages/source/React/router/\"},{\"text\":\"setState使用及原理\",\"link\":\"/pages/source/React/setState/\"}]}]},{\"text\":\"面试题\",\"collapsed\":true,\"items\":[{\"text\":\"Vue\",\"link\":\"/pages/interview/Vue/\"},{\"text\":\"HTML&CSS\",\"link\":\"/pages/interview/HC/\"}]}]},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>